
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author David
 */
public class ExecServer {
    private ServerSocket serverManager;
    private ServerConfig config;
    private static AtomicInteger threadCounter = new AtomicInteger();
    private static final int MaxNumberOfThreadsAllowed = 2;
    private static boolean isServerAvailable = true;

    public ExecServer(){
        try{
            this.config = new ServerConfig();
            this.config.loadConfig("C:\\server\\config.txt");
            this.serverManager = new ServerSocket(this.config.getPort());
        }catch(IOException ex){
            System.out.println("Error creating socket");
        }
    }

    public static boolean getServerAvailability()
    {
        return isServerAvailable;
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        ExecServer myServer = new ExecServer();         
        while(true){

            threadCounter.incrementAndGet();
            
            if(threadCounter.get() >= MaxNumberOfThreadsAllowed)
            {
                isServerAvailable = false;
            }

            myServer.processRequests();
        }
    }

    public void processRequests(){
        try{
            RequestThread requestHandler = new RequestThread(serverManager.accept(), this.config);
            new Thread(requestHandler).start();
        } catch(IOException ex) {
            System.out.println("Error handling Managers request");
        }
    }

    class RequestThread implements Runnable {
        private Socket incoming;
        private BufferedReader input;
        private BufferedOutputStream output;
        private Request request;
        private Response response;
        
        public RequestThread(Socket incoming, ServerConfig config){
            try {
                this.incoming = incoming;
                this.input = new BufferedReader(new InputStreamReader(this.incoming.getInputStream()));
                this.output = new BufferedOutputStream(this.incoming.getOutputStream());
                this.request = new Request();
                this.response = new Response(config);                
            } catch (IOException ex) {
                Logger.getLogger(ExecServer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        @Override
        public void run(){
            System.out.println("Connection established");
            try {                
                this.request.processRequest(input);
                this.response.processRequest(this.request);
                this.response.writeOutput(this.output);
                this.output.flush();
                this.incoming.close();

                //decrement the thread counter
                threadCounter.decrementAndGet();

                if(threadCounter.get() < MaxNumberOfThreadsAllowed)
                {
                    isServerAvailable = true;
                }
                
            } catch (IOException ex) {
                System.out.println("Communication failed");
            }
        }
    }
}
